#include "TimeTreeWidget.h"

#include "TimeTreeWidgetItem.h"

#include "ui_TimeSetPropertyDialog.h"

#include <QMouseEvent>
#include <QPainter>
#include <QVBoxLayout>
#include <QStackedLayout>
#include <QMenu>

TimeTreeWidget::TimeTreeWidget(QWidget *parent, Qt::WindowFlags f)
    : QWidget(parent, f)
    , _setTimeMenu(Q_NULLPTR)
    , _pTimeHeader(Q_NULLPTR)
    , _pTimeTreeWidget(Q_NULLPTR)
{
    this->setMinimumSize(500, 200);

    QStackedLayout *pStacked = new QStackedLayout(this);
    pStacked->setContentsMargins(0, 0, 0, 0);

    _pTimeHeader = new TimeTreeWidgetHeader();
    QObject::connect(_pTimeHeader, SIGNAL(signalRightButtonRelease(QPoint)), this, SLOT(slotRightButtonRelease(QPoint)));
    pStacked->addWidget(_pTimeHeader);
    _pTimeHeader->raise();

    _pTimeTreeWidget = new TimeTreeItemManager();
    QObject::connect(_pTimeHeader, SIGNAL(signalSetDialXPos(int)), _pTimeTreeWidget, SIGNAL(signalSetDialXPos(int)));
    QObject::connect(_pTimeHeader, SIGNAL(signalAddWheelValue(int)), _pTimeTreeWidget, SIGNAL(signalAddWheelValue(int)));
    _pTimeTreeWidget->init();
    pStacked->addWidget(_pTimeTreeWidget);

    pStacked->setStackingMode(QStackedLayout::StackAll);

    _setTimeMenu = new QMenu(this);
    _setTimeMenu->addAction(QStringLiteral("设置任务总时间"));
    _setTimeMenu->addAction(QStringLiteral("转到指定时间"));
    _setTimeMenu->addAction(QStringLiteral("显示当前时间"));
    _setTimeMenu->addAction(QStringLiteral("时间归零"));
}

TimeTreeWidget::~TimeTreeWidget()
{

}

void TimeTreeWidget::slotRightButtonRelease(QPoint pos)
{
    if (_setTimeMenu)
    {
        QAction* pSelect = _setTimeMenu->exec(pos);
        if (pSelect)
        {
            setTimeProperty(pSelect->text());
        }
    }
}

void TimeTreeWidget::setTimeProperty(QString cmd)
{
    if (cmd == QStringLiteral("时间归零"))
    {
        TimeTreeItemManager::s_iCurWheelValue = 0;
        TimeTreeItemManager::s_dCurDialValue = 0.0;
        repaint();
    }
    else if (cmd == QStringLiteral("显示当前时间"))
    {
        TimeTreeItemManager::s_iCurWheelValue = TimeTreeItemManager::s_dCurDialValue - 30;
        if (TimeTreeItemManager::s_iCurWheelValue < TimeTreeItemManager::s_iMinDialValue)
        {
            TimeTreeItemManager::s_iCurWheelValue = TimeTreeItemManager::s_iMinDialValue;
        }
        int numScale = (this->width() - 20 - TimeTreeItemManager::s_leftRect.width() -
                        TimeTreeItemManager::s_leftRect.x()) / TimeTreeItemManager::s_iDialGap;
        if (TimeTreeItemManager::s_iCurWheelValue > TimeTreeItemManager::s_iMaxDialValue - numScale)
        {
            TimeTreeItemManager::s_iCurWheelValue = TimeTreeItemManager::s_iMaxDialValue - numScale;
        }
        repaint();
    }
    else if (cmd == QStringLiteral("设置任务总时间"))
    {
        TimeSetPropertyDialog dialog;
        dialog.setWindowTitle(QStringLiteral("设置任务总时间"));
        dialog.ui->label->setText(QStringLiteral("设置任务总时间"));
        int numScale = (this->width() - 20 - TimeTreeItemManager::s_leftRect.width() -
                        TimeTreeItemManager::s_leftRect.x()) / TimeTreeItemManager::s_iDialGap;
        dialog.ui->spinBox->setRange(TimeTreeItemManager::s_iMinDialValue + numScale, TimeTreeItemManager::s_iMaxDialValue * 10);
        dialog.ui->spinBox->setValue(TimeTreeItemManager::s_iMaxDialValue);
        if (dialog.exec() == QDialog::Accepted)
        {
            TimeTreeItemManager::s_iMaxDialValue = dialog.ui->spinBox->value();
            repaint();
        }
    }
    else if (cmd == QStringLiteral("转到指定时间"))
    {
        TimeSetPropertyDialog dialog;
        dialog.setWindowTitle(QStringLiteral("转到指定时间"));
        dialog.ui->label->setText(QStringLiteral("转到指定时间"));
        dialog.ui->spinBox->setRange(TimeTreeItemManager::s_iMinDialValue, TimeTreeItemManager::s_iMaxDialValue);
        dialog.ui->spinBox->setValue(TimeTreeItemManager::s_dCurDialValue);
        if (dialog.exec() == QDialog::Accepted)
        {
            TimeTreeItemManager::s_dCurDialValue = dialog.ui->spinBox->value();
            setTimeProperty(QStringLiteral("显示当前时间"));
        }
    }
}

int TimeTreeItemManager::s_iCurWheelValue = 0;
double TimeTreeItemManager::s_dCurDialValue = 10.0;
int TimeTreeItemManager::s_iMinDialValue = 0;
int TimeTreeItemManager::s_iMaxDialValue = 5000;
int TimeTreeItemManager::s_iDialGap = 6;
QRect TimeTreeItemManager::s_leftRect = QRect(0, 0, 230, 30);
int TimeTreeItemManager::s_iTextSide = 5;
int TimeTreeItemManager::s_iTriangle = 12;
int TimeTreeItemManager::s_iWhiteCircle = 4;

TimeTreeItemManager::TimeTreeItemManager(QWidget *parent, Qt::WindowFlags f)
    : QWidget(parent, f)
    , _isDragging(false)
    , _pSpaceHeader(new QSpacerItem(20, 53, QSizePolicy::Fixed, QSizePolicy::Fixed))
    , _pSpaceEnd(new QSpacerItem(20, 0, QSizePolicy::Fixed, QSizePolicy::Fixed))
    , _iItemCurWheelValue(0)
    , _iItemMinWheelValue(0)
    , _iItemMaxWheelValue(0)
{

}

TimeTreeItemManager::~TimeTreeItemManager()
{

}

void TimeTreeItemManager::init()
{
    this->setMinimumSize(500, 200);

    QObject::connect(this, SIGNAL(signalSetDialXPos(int)), this, SLOT(slotSetDialXPos(int)));
    QObject::connect(this, SIGNAL(signalAddWheelValue(int)), this, SLOT(slotAddWheelValue(int)));
    QObject::connect(this, SIGNAL(signalWheelEventDelta(int)), this, SLOT(slotWheelEventDelta(int)));

    QVBoxLayout *pLayout = new QVBoxLayout(this);
    pLayout->setContentsMargins(0, 0, 0, 0);
    pLayout->setSpacing(0);

    pLayout->addSpacerItem(_pSpaceHeader);

    TimeTreeWidgetItem* pFirstItem = Q_NULLPTR;

    int itemNum = 0;
    for (int i = 0; i < 80; ++i )
    {
        TimeTreeWidgetItem* pItem= new TimeTreeWidgetItem();
        QObject::connect(pItem, SIGNAL(signalSetDialXPos(int)), this, SIGNAL(signalSetDialXPos(int)));
        QObject::connect(pItem, SIGNAL(signalAddWheelValue(int)), this, SIGNAL(signalAddWheelValue(int)));
        QObject::connect(pItem, SIGNAL(signalClickedSelected(int)), this, SLOT(slotClickedSelected(int)));
        QObject::connect(pItem, SIGNAL(signalDoubleClickedSelected()), this, SLOT(slotDoubleClickedSelected()));
        QObject::connect(pItem, SIGNAL(signalWheelEventDelta(int)), this, SLOT(slotWheelEventDelta(int)));
        pLayout->addWidget(pItem);
        if (i % 4 != 0)
        {
            pItem->setLevelNum(2);
            pItem->setId(pFirstItem->getId().append("-").append(QString::number(i % 4)));
            _mapFirstToSecondItem[pFirstItem].append(pItem);
        } else {
            pFirstItem = pItem;
            ++itemNum;
            _mapNumToFirstItem[itemNum] = pFirstItem;
            pFirstItem->setId(QString(QStringLiteral("模型组")).append(QString::number(itemNum)));
        }
        _listShowItems.append(pItem);
    }

    pLayout->addSpacerItem(_pSpaceEnd);

    QSpacerItem* pSpaceItem = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
    pLayout->addSpacerItem(pSpaceItem);
    updateShowItem();
}

void TimeTreeItemManager::slotSetDialXPos(int xPos)
{
    int xStartPos = s_leftRect.width() + s_leftRect.x(); // 刻度线开始位置
    if (xPos < xStartPos)
    {
        return;
    }

    s_dCurDialValue = s_iCurWheelValue + (xPos - xStartPos) / s_iDialGap;
    if (s_dCurDialValue > s_iMaxDialValue)
    {
        s_dCurDialValue = s_iMaxDialValue;
    }

    repaint();
}

void TimeTreeItemManager::slotAddWheelValue(int wheelDelta)
{
    int numScale = (this->width() - 20 - s_leftRect.width() - s_leftRect.x()) / s_iDialGap;
    if ( wheelDelta == 0 || (s_iCurWheelValue <= s_iMinDialValue && wheelDelta < 0)
     || (s_iCurWheelValue + numScale >= s_iMaxDialValue && wheelDelta > 0))
    {
        return;
    }

    if (s_iCurWheelValue > s_iMinDialValue && s_iCurWheelValue + wheelDelta < s_iMinDialValue)
    {
        s_iCurWheelValue = s_iMinDialValue;
        repaint();
        return;
    }

    if (s_iCurWheelValue + numScale < s_iMaxDialValue && s_iCurWheelValue + wheelDelta + numScale > s_iMaxDialValue)
    {
        s_iCurWheelValue = s_iMaxDialValue - numScale;
        repaint();
        return;
    }

    s_iCurWheelValue += wheelDelta;
    repaint();
}

void TimeTreeItemManager::slotClickedSelected(int )
{
    TimeTreeWidgetItem* pItem = dynamic_cast<TimeTreeWidgetItem*>(sender());
    if (pItem  == Q_NULLPTR)
    {
        return;
    }
    selectOneItem(pItem);
}

void TimeTreeItemManager::slotDoubleClickedSelected()
{
    TimeTreeWidgetItem* pItem = dynamic_cast<TimeTreeWidgetItem*>(sender());
    if (pItem  == Q_NULLPTR)
    {
        return;
    }

    if(_mapFirstToSecondItem.contains(pItem))
    {
        int num = _mapFirstToSecondItem[pItem].size();
        for (int i = 0; i < num; ++i)
        {
            TimeTreeWidgetItem* pCur = _mapFirstToSecondItem[pItem].at(i);
            pCur->SetItemVisible(!pCur->isItemVisible());
            pCur->setVisible(pCur->isItemVisible());
        }
        updateShowItem();
    }
    selectOneItem(pItem);
}

void TimeTreeItemManager::slotWheelEventDelta(int delta)
{
    if (_pSpaceHeader)
    {
        _iItemCurWheelValue -= delta;
        if (_iItemMaxWheelValue - _iItemMinWheelValue < this->height() - 53)
        {
            _iItemCurWheelValue = 0;
        }

        if (_iItemCurWheelValue < _iItemMinWheelValue)
        {
            _iItemCurWheelValue = _iItemMinWheelValue;
        }
        if (_iItemCurWheelValue > 0 && _iItemCurWheelValue > _iItemMaxWheelValue - this->height() + 53)
        {
            _iItemCurWheelValue = _iItemMaxWheelValue - this->height() + 53;
        }

        int numhide = _iItemCurWheelValue / (s_leftRect.height() + 3);
        int numAdjust = _iItemCurWheelValue % (s_leftRect.height() + 3);
        int showRange = this->height() - 53 + numAdjust;
        int numShow = showRange / (s_leftRect.height() + 3);
        int showAdjust = showRange % (s_leftRect.height() + 3);

        int showItemHeight = 0;
        for (int i = 0; i < _listShowItems.size(); ++i)
        {
            bool visible = false;
            if (i >= numhide && i <= numhide + numShow)
            {
                visible = true;
                showItemHeight += (s_leftRect.height() + 3);
            }
            _listShowItems.at(i)->setVisible(visible);
            _listShowItems.at(i)->setFixedHeight(s_leftRect.height() + 3);
        }

        if (showAdjust > 0 && numShow + numhide < _listShowItems.size())
        {
            _listShowItems.at(numShow + numhide)->setFixedHeight(showAdjust);
            showItemHeight += showAdjust;
        }

        _pSpaceHeader->changeSize(20, 53 - numAdjust, QSizePolicy::Fixed, QSizePolicy::Fixed);
        int endSpace = this->height() - (53 - numAdjust) - showItemHeight;
        _pSpaceEnd->changeSize(20, endSpace, QSizePolicy::Fixed, QSizePolicy::Fixed);
        this->layout()->update();
    }
}

void TimeTreeItemManager::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::RightButton)
    {
        return;
    }

    int xStartPos = s_leftRect.width() + s_leftRect.x(); // 刻度线开始位置
    int dialXPos = (s_dCurDialValue - s_iCurWheelValue) * s_iDialGap + xStartPos;

    if (abs(event->pos().x() - dialXPos) < s_iDialGap)
    {
        _isDragging = true;
    }
}

void TimeTreeItemManager::mouseReleaseEvent(QMouseEvent *)
{
    _isDragging = false;
}

void TimeTreeItemManager::mouseDoubleClickEvent(QMouseEvent *event)
{
    emit signalSetDialXPos(event->pos().x());
}

void TimeTreeItemManager::mouseMoveEvent(QMouseEvent *event)
{
    if (_isDragging)
    {
        int xStartPos = s_leftRect.width() + s_leftRect.x(); // 刻度线开始位置
        int cursorXPos = event->pos().x();
        if (cursorXPos < xStartPos)
        {
            emit signalAddWheelValue(-1);
            cursorXPos = xStartPos;
        }
        else if (cursorXPos > this->width())
        {
            emit signalAddWheelValue(1);
            cursorXPos = this->width() - s_iDialGap;
        }
        emit signalSetDialXPos(cursorXPos);
    }
}

void TimeTreeItemManager::wheelEvent(QWheelEvent *event)
{
    emit signalWheelEventDelta(event->delta() / 9);
}

void TimeTreeItemManager::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter painter(this);

    painter.setRenderHint(QPainter::Antialiasing, true);    // 反走样

    /* 绘制背景颜色 */
    painter.setPen(QPen(QColor("lightgray"), 3));    // 设置画笔颜色、宽度
    painter.setBrush(QColor("lightgray"));  // 设置画刷颜色 //darkcyan	#008B8B	0,139,139
    painter.drawRect(0, 0, this->width(), this->height());

    int xStartPos = s_leftRect.width() + s_leftRect.x(); // 刻度线开始位置
    if (xStartPos > this->width())
    {
        return;
    }
    int curDialValue = s_dCurDialValue;
    int numScale = (this->width()- xStartPos) / s_iDialGap;
    int dialXPos = -1;
    if (curDialValue >= s_iCurWheelValue && curDialValue < s_iCurWheelValue + numScale)
    {
        int xAdd = (curDialValue - s_iCurWheelValue) * s_iDialGap;
        dialXPos = xStartPos + xAdd;
    }
    if (dialXPos > 0 && dialXPos < this->width())
    {
        painter.setPen(QPen(QColor("red"), 1.8));    // 设置画笔颜色、宽度
        painter.drawLine(QPoint(dialXPos, 0), QPoint(dialXPos, this->height()));
    }
}

void TimeTreeItemManager::resizeEvent(QResizeEvent *)
{
    slotWheelEventDelta(0);
}

void TimeTreeItemManager::selectOneItem(TimeTreeWidgetItem *pSelected)
{
    QMap<TimeTreeWidgetItem *, QListTreeItem>::iterator i = _mapFirstToSecondItem.begin();
    while (i != _mapFirstToSecondItem.end()) {
//          cout << i.key() << ": " << i.value() << endl;
        i.key()->setSelected(false);
        int num = i.value().size();
        for (int j = 0; j < num; ++j)
        {
            TimeTreeWidgetItem* pCur = i.value().at(j);
            pCur->setSelected(false);
        }
        ++i;
    }
    pSelected->setSelected(true);
    repaint();
}

void TimeTreeItemManager::updateShowItem()
{
    _listShowItems.clear();
    QMap<int, TimeTreeWidgetItem*>::iterator i = _mapNumToFirstItem.begin();
    while (i != _mapNumToFirstItem.end()) {
//          cout << i.key() << ": " << i.value() << endl;
        _listShowItems.push_back(i.value());
        int num = _mapFirstToSecondItem[i.value()].size();
        for (int j = 0; j < num; ++j)
        {
            TimeTreeWidgetItem* pCur = _mapFirstToSecondItem[i.value()].at(j);
            if (pCur->isItemVisible())
            {
                _listShowItems.append(pCur);
            }
        }
        ++i;
    }

    _iItemMaxWheelValue = _listShowItems.size() * (s_leftRect.height() + 3) - 3;
    slotWheelEventDelta(0);
}

TimeSetPropertyDialog::TimeSetPropertyDialog(QWidget *parent, Qt::WindowFlags f)
    : QDialog(parent, f)
    , ui(new Ui::TimeSetPropertyDialog())
{
    ui->setupUi(this);
}

TimeSetPropertyDialog::~TimeSetPropertyDialog()
{
    delete ui;
}
